

local ToolBox = commonlib.inherit(commonlib.ToolBase);

ToolBox:Property("ClassName", "ToolBox");
ToolBox:Property("Blockly");

function ToolBox:ctor()
    self.__category_list__ = {};
    self.__block_map__ = {};
    self.__xml_text__ = "";
    self.__current_category_name__ = "";
    self.__width__, self.__height__ = 0, 0;
    self.__content_width__, self.__content_height__ = 0, 0;
    self.__category_text_height__ = 0;
    -- self.__category_text_height__ = 24;
    self.__category_width__ = 60;
    self.__category_height__ = 60;
    self.__category_total_width__ = 60;
    self.__category_total_height__ = 60;
    self.__offset_y__ = 0;
end

function ToolBox:Init(blockly)
    self:SetBlockly(blockly);

    return self;
end

function ToolBox:SetLanguage(language)
    if (self.__language__ == language) then return end 
    self.__language__ = language;
    self.__category_list__ = {};

    local blockly = self:GetBlockly();
    for _, category in ipairs(blockly.__all_category_list__) do
        local clone_category = {
            name = category.name,
            text = category.text,
            color = category.color,
            blocklist = {};
        }

        for _, blocktype in ipairs(category.blocktypes) do
            local opt = blockly.__all_block_map__[blocktype];
            if (opt and not opt.hideInToolbox) then
                local block = blockly:NewBlock(blocktype);
                block:SetColor(clone_category.color);
                table.insert(clone_category.blocklist, block);
            end
        end

        if (#clone_category.blocklist > 0) then
            table.insert(self.__category_list__, clone_category);
        end
    end

    self:UpdateLayout();
end

function ToolBox:SetXmlText(xmltext)
    if (self.__xml_text__ == xmltext) then return end 
    self.__xml_text__ = xmltext;
    local xmlnodes = commonlib.XmlDecode(xmltext);
    if (not xmlnodes) then return end 

    local blockly = self:GetBlockly();
    local __all_category_map__ = blockly.__all_category_map__;

    self.__category_list__ = {};
    for _, xmlnode in ipairs(xmlnodes) do
        local attr = xmlnode.attr; -- <category name="motion" text="运动" color="#000000"></category>
        local category = __all_category_map__[attr.name];
        local clone_category = {
            name = attr.name or category.name,
            text = attr.text or category.text,
            color = attr.color or category.color,
            blocklist = {},
        }
        for _, subxmlnode in ipairs(xmlnode) do
            local attr = subxmlnode.attr;  -- <block type="Move"></block>
            local block = blockly:NewBlock(attr.type);
            if (block and not attr.hideInToolbox) then 
                block:SetColor(clone_category.color);
                table.insert(clone_category.blocklist, block);
            end
        end
        if (#clone_category.blocklist > 0) then
            table.insert(self.__category_list__, clone_category);
        end
    end

    self:UpdateLayout();
end

function ToolBox:UpdateLayout()
    local blockly = self:GetBlockly();
    local UnitSize = self:GetBlockly():GetUnitSize();
    local offsetX, offsetY, margin_top, margin_bottom = 25, 0, 3, 3;
    for _, category in ipairs(self.__category_list__) do
        category.__offset_y__ = offsetY * UnitSize;
        offsetY = offsetY + self.__category_text_height__ / UnitSize;
        for _, block in ipairs(category.blocklist) do
            offsetY = offsetY + margin_top; -- 间隙
            block:SetToolBoxBlock(true);
            local widthUnitCount, heightUnitCount = block:UpdateWidthHeightUnitCount();
            block:SetLeftTopUnitCount(offsetX, offsetY);
            block:UpdateLeftTopUnitCount();
            offsetY = offsetY + heightUnitCount + margin_bottom;
        end
    end
    self.__current_category_name__ = self.__category_list__[1] and self.__category_list__[1].name or "";
    self.__category_total_width__ = self.__category_width__;
    self.__category_total_height__ = self.__category_height__ * (#self.__category_list__);
    self.__content_height__ = (offsetY + margin_top) * UnitSize;
end

function ToolBox:SetWidthHeight(width, height)
    self.__width__, self.__height__ = width or self.__width__, height or self.__height__;
end

function ToolBox:GetWidthHeight()
    return self.__width__, self.__height__;
end

function ToolBox:Render()
    local blockly = self:GetBlockly();
    local width, height = self:GetWidthHeight();

    blockly:Save();
    blockly:DrawRectangle(0, 0, width, height, false, false);
    blockly:Clip();

    -- toolbox background
    blockly:SetBrushColor(0xC8C8C8FF);
    blockly:DrawRectangle(0, 0, width, height);

    -- category background
    local __category_width__ = self.__category_width__;
    local __category_height__ = self.__category_height__;
    blockly:SetBrushColor(0x363536ff);
    blockly:DrawRectangle(0, 0, __category_width__, height);
  
    -- category 
    blockly:SetFontSize(12);
    local __mouse_x__, __mouse_y__ = blockly:GetMouseXY();
    local __x__, __y__ = blockly:ScreenXYToElementXY(__mouse_x__, __mouse_y__);
    local __text_height__, __padding__ = 20, 8;
    local __circle_radius__ = (__category_height__ - __text_height__) / 2 - __padding__;
    for i, category in ipairs(self.__category_list__) do
        local __category_offset_y__ = (i - 1) * __category_height__;
        
        -- category select cover
        if (category.name == self.__current_category_name__) then
            blockly:SetBrushColor(0x585D5EFF);
            blockly:DrawRectangle(0, __category_offset_y__, __category_width__, __category_height__);
        end

        -- category circle
        blockly:SetBrushColor(category.color);
        blockly:DrawCircle(__category_width__ / 2, __category_offset_y__ + __padding__ + __circle_radius__, __circle_radius__);

        -- category text
        blockly:SetFontStringColor(category.color);
        -- hover change font color
        if (__x__ > 0 and __x__ < __category_width__ and __category_offset_y__ < __y__ and __y__ < (__category_offset_y__ + __category_height__)) then 
            blockly:SetFontStringColor(0xffffffff);
        end
        blockly:DrawText(0, __category_offset_y__ + __padding__ + __circle_radius__ * 2, __category_width__, __text_height__, category.text or category.name, "center", "center");
    end

    -- category block list
    blockly:Translate(0, -self.__offset_y__);
    for _, category in ipairs(self.__category_list__) do
        for _, block in ipairs(category.blocklist) do
            block:Render();
        end
    end
    blockly:Translate(0, self.__offset_y__);

    -- right border line
    blockly:SetPenColor(0xff);
    blockly:DrawLine(width, 0, width, height);

    blockly:Restore();
end

function ToolBox:GetOffsetYUnitCount()
    return math.floor(self.__offset_y__ / self:GetBlockly():GetUnitSize());
end

function ToolBox:CloneBlock(block)
    local blockly = self:GetBlockly();
    local UnitSize = blockly:GetUnitSize();
    local clone = blockly:NewBlock(block:GetType());
    clone:UpdateWidthHeightUnitCount();
    local leftUnitCount, topUnitCount = block:GetLeftTopUnitCount();
    local viewLeftUnitCount, viewTopUnitCount = leftUnitCount, topUnitCount - blockly:GetToolBox():GetOffsetYUnitCount();
    local logicLeftUnitCount, logicTopUnitCount = viewLeftUnitCount + math.floor(blockly.__offset_x__ / UnitSize), viewTopUnitCount + math.floor(blockly.__offset_y__ / UnitSize);
    clone:SetLeftTopUnitCount(logicLeftUnitCount, logicTopUnitCount);
    clone:UpdateLeftTopUnitCount();
    return clone;
end

function ToolBox:GetMouseUI(x, y)
    if (x > self.__width__) then return end 
    if (x < self.__category_width__) then return self end
    y = y + self.__offset_y__;
    self.__mouse_ui__ = nil;
    for _, category in ipairs(self.__category_list__) do
        for _, block in ipairs(category.blocklist) do
            local ui = block:GetMouseUI(x, y);
            if (ui) then 
                self.__mouse_ui__ = ui;
                return self;
            end 
        end
    end

    return self;
end

function ToolBox:OnMouseDown(event)
    if (self.__mouse_ui__) then
        local block = self:CloneBlock(self.__mouse_ui__:GetBlock());
        self:GetBlockly():SetMouseCaptureUI(block);
        block:OnMouseDown(event);
        return;
    end

    local x, y = self:GetBlockly():ScreenXYToElementXY(event:GetXY());
    if (x > self.__width__) then return end 

    if (x < self.__category_width__) then
        local index = math.ceil(y / self.__category_height__);
        local category = self.__category_list__[index];
        if (category) then 
            self.__current_category_name__ = category.name;
            self.__offset_y__ = category.__offset_y__;
        end
        return self;
    else

    end
end

function ToolBox:OnMouseMove(x, y)
end

function ToolBox:OnMouseUp(x, y)
end

function ToolBox:OnMouseWheel(event)
end

return ToolBox;